package cn.gson.querydsl.dao;

import cn.gson.querydsl.util.CheckUtils;
import jakarta.persistence.Id;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.noear.solon.Solon;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;

/**
 * <p>****************************************************************************</p>
 * <ul style="margin:15px;">
 * <li>Description : </li>
 * <li>Version     : 1.0</li>
 * <li>Creation    : 2024年07月19日</li>
 * <li>@author     : ____′↘夏悸</li>
 * </ul>
 * <p>****************************************************************************</p>
 */
public class HibernateDaoImpl implements HibernateDao {
    private Class<?> entityClass;
    private String idColumnName = null;
    private SessionFactory sessionFactory;

    public HibernateDaoImpl(Class<?> entityClass) {
        this.entityClass = entityClass;
    }

    @Override
    public List findAll() {
        return getSession().createQuery(
                "select e from " + entityClass.getSimpleName() + " e", entityClass
        ).list();
    }

    @Override
    public Object findById(Serializable id) {
        CheckUtils.checkNotNull(id, "Id不能为空");
        return getSession().find(entityClass, id);
    }

    @Override
    public Object saveOrUpdate(Object entity) {
        CheckUtils.checkNotNull(entity, "保存对象不能为空");
        Session session = getSession(true);
        session.persist(entity);// 保存或更新
        return entity;
    }

    @Override
    public List saveAll(List entities) {
        CheckUtils.checkListNotNull(entities, "保存列表不能为空");
        CheckUtils.isFalseAssert(entities.size() > 500, "批量插入的数据不应该超过500，数据太多会导致hibernate检查上下文数据时执行大量计算，拖慢性能！");
        Session session = getSession(true);
        for (Object e : entities)
            session.persist(e);// 保存或更新
        return entities;
    }

    @Override
    public List saveAllAndFlush(List entities) {
        List list = saveAll(entities);
        flush();
        return list;
    }

    @Override
    public void delete(Object entity) {
        CheckUtils.checkNotNull(entity, "删除对象不能为空");
        Session session = getSession(true);
        session.remove(entity);
        session.flush();
    }

    @Override
    public int deleteById(Serializable id) {
        CheckUtils.checkNotNull(id, "Id不能为空");
        return getSession(true).createMutationQuery(
                "delete from " + entityClass.getSimpleName() + " where " + getIdColumnName() + "=?1").setParameter(1, id).executeUpdate();
    }

    @Override
    public void deleteAll(List entities) {
        CheckUtils.checkListNotNull(entities, "删除列表不能为空");
        Session session = getSession(true);
        for (Object e : entities)
            session.remove(e);// 保存或更新
    }

    @Override
    public boolean isExistsById(Serializable id) {
        List<Boolean> list = getSession().createQuery(
                        "select count(e)>0 from " + entityClass.getSimpleName() + " e where " + getIdColumnName() + "=?1",
                        Boolean.class
                )
                .setParameter(1, id).list();
        return list.get(0);
    }

    @Override
    public long countAll() {
        Long count = getSession().createQuery(
                "select count(e) from " + entityClass.getSimpleName() + " e",
                Long.class
        ).getSingleResult();
        return count;
    }

    /**
     * 通常是在最后提交阶段执行，中途执行会花费相对昂贵的java代价，线程不安全，多次执行可能会报空指针问题。
     */
    @Override
    public void flush() {
        getSession().flush();
    }

    public Session getSession() {
        return getSession(false);
    }

    private Session getSession(boolean check) {
        if (sessionFactory == null) {
            sessionFactory = Solon.context().getBean(SessionFactory.class);
            CheckUtils.isTrueAssert(sessionFactory != null, "尚未装配 SessionFactory bean");
        }
        Session session = sessionFactory.openSession();
        if (check && !session.getTransaction().isActive())
            throw new IllegalStateException("事务还未开启：Transaction is not open, update/delete need transaction");

        return session;
    }

    private String getIdColumnName() {
        if (idColumnName != null)
            return idColumnName;
        Field[] fields = entityClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Id.class)) {
                idColumnName = field.getName();
                return idColumnName;
            }
        }
        throw new IllegalArgumentException("当前实体类不存在@Id列：" + entityClass.getName());
    }
}
